package com.cm.projectx.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cm.projectx.constants.PriceReportConstants;
import com.cm.projectx.entity.PriceTask;
import com.cm.projectx.entity.ProductInfo;
import com.cm.projectx.entity.ProductPriceReportDetail;
import com.cm.projectx.entity.TaskProcessRelation;
import com.cm.projectx.mapper.PriceTaskMapper;
import com.cm.projectx.mapper.ProductInfoMapper;
import com.cm.projectx.mapper.ProductPriceReportDetailMapper;
import com.cm.projectx.mapper.TaskProcessRelationMapper;
import com.cm.projectx.response.Result;
import com.cm.projectx.service.IProductPriceReportDetailService;
import com.cm.projectx.util.PoiHelper;
import com.cm.projectx.vo.PriceSearchVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

//商品填报详情查询
@Slf4j
@Service
@RequiredArgsConstructor
public class ProductPriceReportDetailServiceImpl extends ServiceImpl<ProductPriceReportDetailMapper, ProductPriceReportDetail> implements IProductPriceReportDetailService {
    private final ProductPriceReportDetailMapper productPriceReportDetailMapper;
    private final ProductInfoMapper productInfoMapper;
    private final PriceTaskMapper priceTaskMapper;
    private final TaskProcessRelationMapper taskProcessRelationMapper;

    @Value("${spring.file.template.path}")
    private String templateFilePath;
    private final List<String> NUMBER_STR = Arrays.asList("一、", "二、", "三、", "四、", "五、", "六、", "七、", "八、", "九、", "十、", "十一、", "十二、", "十三、", "十四、", "十五、", "十六、", "十七、", "十八、", "十九、");

    private static Map<String, Integer> SHEET_FIELD_CONFIG = new HashMap() {{
        put("no", 0);
        put("name", 1);
        put("kind", 2);
        put("unit", 3);
        put("avgPrice", 4);
    }};

    private static Set<String> templateCodeSet = new HashSet<>(Arrays.asList("T001", "T002", "T003", "T005", "T006"));

    @Override
    public Map<String, List<Map<String, Object>>> selectPage(PriceSearchVo priceSearchVo) {
        HashMap<String, List<Map<String, Object>>> result = new HashMap<>();

        if (StrUtil.isEmpty(priceSearchVo.getTaskId())) {
            priceSearchVo.setTaskId("-1");
        }
        if (StrUtil.isEmpty(priceSearchVo.getDatePicker())) {
            priceSearchVo.setDatePicker("-1");
        }

        //参数处理
        ArrayList<Map<String, Object>> allMonitorPoints = new ArrayList<>();
        if (StrUtil.isNotEmpty(priceSearchVo.getMonitorPoints())) {
            System.out.println("监测点传值=" + priceSearchVo.getMonitorPoints());
            List<String> monitorPointIds = StrUtil.split(priceSearchVo.getMonitorPoints(), StrUtil.COMMA).stream().map(
                    s -> {
                        List<String> monitorPointInfo = StrUtil.split(s, StrPool.COLON);
                        HashMap<String, Object> m = MapUtil.newHashMap(4);
                        m.put("id", monitorPointInfo.get(0));
                        m.put("name", monitorPointInfo.get(1));
                        allMonitorPoints.add(m);
                        return monitorPointInfo.get(0);
                    }
            ).collect(Collectors.toList());
            priceSearchVo.setMonitorPointList(monitorPointIds);
        } else {
            priceSearchVo.setMonitorPointList(Collections.singletonList("-1"));
        }

        //获取各区县的价格数据
        List<Map<String, Object>> basePriceData = productPriceReportDetailMapper.getMonitorPointPriceData(priceSearchVo);
        //数据判空
        if (CollUtil.isEmpty(basePriceData)) {
            return result;
        }
        result.put("priceResult", generateReportData(basePriceData));

        //过滤有数据的监测点
        List<String> monitorPointList = basePriceData.stream()
                .map(d -> StrUtil.toString(d.get("monitorPoint")))
                .collect(Collectors.toList());
        List<Map<String, Object>> monitorPointResult = allMonitorPoints.stream()
                .filter(m -> CollUtil.contains(monitorPointList, StrUtil.toString(m.get("id"))))
                .collect(Collectors.toList());
        result.put("monitorPointResult", monitorPointResult);

        return result;
    }

    @Override
    public Map<String, List<Map<String, Object>>> selectPageV3(PriceSearchVo priceSearchVo, PriceTask priceTask) {
        HashMap<String, List<Map<String, Object>>> result = new HashMap<>();

        if (StrUtil.isEmpty(priceSearchVo.getTaskId())) {
            priceSearchVo.setTaskId("-1");
        }
        if (StrUtil.isEmpty(priceSearchVo.getDatePicker())) {
            priceSearchVo.setDatePicker("-1");
        }

        //提取任务中所有商品的监测点
        ArrayList<Map<String, Object>> allMonitorPoints = extractMonitorsFromTask(priceTask);
        //提取任务中所有商品的价格预警幅度
        Map<String, String> productPriceAlarmMapping = extractPriceAlarmFromTask(priceTask);

        //设置查询监测点
        List<String> monitorIds = allMonitorPoints.stream().map(m -> (String)m.get("id")).collect(Collectors.toList());
        priceSearchVo.setMonitorPointList(monitorIds);


        //获取商品指标数据
        List<Map<String, Object>> basePriceData = productPriceReportDetailMapper.getMonitorPointPriceDataV3(priceSearchVo);
        log.info("basePriceData={}", JSONUtil.toJsonStr(basePriceData));


        //判空
        if (CollUtil.isEmpty(basePriceData)) {
            return result;
        }
        List<Map<String, Object>> priceResult = generateReportDataV3(basePriceData, allMonitorPoints, productPriceAlarmMapping, priceTask);
        JSONArray jsonArray = JSONUtil.parseArray(priceTask.getProductMonitorRelations());
        List<Map<String, Object>> newL = new ArrayList<>();
        jsonArray.forEach(obj -> {
            JSONObject one = (JSONObject) obj;
            String productId = one.getStr("productId");
            newL.addAll(priceResult.stream().filter(p -> p.get("productId").equals(productId)).collect(Collectors.toList()));
        });
        log.info("newL={}", JSONUtil.toJsonStr(newL));


        //返回监测点信息
        result.put("monitorPointResult", allMonitorPoints);

        //需要增加分类的统计表
        //if (priceTask.getDkTemplateTypesCode().equals("T001")){
        if (templateCodeSet.contains(priceTask.getDkTemplateTypesCode())){
            //分组，然后增加分类
            if (CollectionUtil.isNotEmpty(newL)){
                List<String> pTypeList = newL.stream().map(one -> one.get("pType").toString()).distinct().collect(Collectors.toList());
                //增加分类
                List<Map<String, Object>> finalResult = new ArrayList<>();
                AtomicInteger index = new AtomicInteger();
                //分类的序号使用
                AtomicInteger typeIndex = new AtomicInteger(1);
                pTypeList.forEach(type -> {
                    HashMap<String, Object> type_record = new HashMap<>();
                    type_record.put("no", "");
                    type_record.put("name", typeIndex.getAndIncrement() + "、" + type);
                    type_record.put("pType", type);
                    finalResult.add(type_record);
                    List<Map<String, Object>> list = priceResult.stream().filter(p -> p.get("pType").equals(type)).collect(Collectors.toList());
                    list.forEach(p->p.put("no", index.incrementAndGet()));
                    finalResult.addAll(list);
                });
                log.info("finalResult={}", JSONUtil.toJsonStr(finalResult));
                result.put("priceResult", finalResult);
                log.info("result={}", JSONUtil.toJsonStr(result));
                return result;
            }
        }
        result.put("priceResult", newL);
        log.info("result={}", JSONUtil.toJsonStr(result));
        return result;
    }

    /**
     * 提取任务中所有商品的价格预警幅度
     * @param priceTask
     * @return
     */
    private Map<String, String> extractPriceAlarmFromTask(PriceTask priceTask) {
        Map<String, String> alarmMap = new HashMap<>();

        String productMonitorRelations = priceTask.getProductMonitorRelations();
        if(StrUtil.isNotEmpty(productMonitorRelations)){
            JSONArray productArray = JSONUtil.parseArray(productMonitorRelations);
            for (Object o : productArray) {
                JSONObject product = (JSONObject) o;
                String id = (String) product.get("productId");
                Float alarmValue = ((BigDecimal) product.get("floatingValue")).floatValue();
                alarmMap.put(id, String.format("%.0f", alarmValue * 100) + "%");
            }
        }
        return alarmMap;
    }

    /**
     * 从任务信息中提取监测点
     * @param priceTask
     * @return
     */
    private ArrayList<Map<String, Object>> extractMonitorsFromTask(PriceTask priceTask) {
        HashSet<String> monitorIdSet = new HashSet<>();
        ArrayList<Map<String, Object>> monitorPoints = new ArrayList<>();

        String productMonitorRelations = priceTask.getProductMonitorRelations();
        if(StrUtil.isNotEmpty(productMonitorRelations)){
            JSONArray productArray = JSONUtil.parseArray(productMonitorRelations);
            for (Object o : productArray) {
                JSONObject product = (JSONObject) o;
                JSONArray monitors = (JSONArray) product.get("monitors");
                if(CollUtil.isNotEmpty(monitors)){
                    for (Object monitor : monitors) {
                        JSONObject monitorObj = (JSONObject) monitor;
                        HashMap<String, Object> m = MapUtil.newHashMap(4);
                        String monitorId = StrUtil.toString(monitorObj.get("monitorId"));
                        if(monitorIdSet.add(monitorId)){
                            m.put("id", monitorObj.get("monitorId"));
                            m.put("name", monitorObj.get("monitorName"));
                            monitorPoints.add(m);
                        }
                    }
                }
            }
        }
        log.info("任务的所有监测点id=" + monitorIdSet);

        return monitorPoints;
    }

    @Override
    public Map<String, Object> exportExcel(PriceSearchVo priceSearchVo) {
        //方法返回excel文件信息
        Map<String, Object> exportFileInfo = new HashMap<>(4);

        //加载模板文件
        InputStream stream = FileUtil.getInputStream(templateFilePath + "priceMonitorV2.xlsx");
        XSSFWorkbook workbook;
        try {
            workbook = new XSSFWorkbook(stream);

            Map<String, List<Map<String, Object>>> queryData = selectPage(priceSearchVo);
            List<Map<String, Object>> priceResult = queryData.get("priceResult");
            List<Map<String, Object>> monitorPointResult = queryData.get("monitorPointResult");
            if(CollUtil.isEmpty(priceResult) || CollUtil.isEmpty(monitorPointResult)){
                String fileName = getReportTitle(priceSearchVo);
                exportFileInfo.put("excel_file_name", fileName + ".xlsx");
                exportFileInfo.put("excel_file_content", workbook);
                return exportFileInfo;
            }

            //设置表头标题
            XSSFSheet sheet = workbook.getSheet("Sheet3");
            XSSFRow titleRow = sheet.getRow(0);
            XSSFCell titleCell = titleRow.getCell(0);
            String newTitle = getReportTitle(priceSearchVo);
            titleCell.setCellValue(newTitle);

            //设置第二行日期
            XSSFRow dateRow = sheet.getRow(1);
            XSSFCell dateCell = dateRow.getCell(0);
            String dateStr = priceSearchVo.getDatePicker().replace("-", "年")
                    .replace("-", "月") + "日";
            dateCell.setCellValue(dateStr);

            //设置第三行表头监测点名称
            XSSFRow minitorPointRow = sheet.getRow(2);
            XSSFRow minitorPointRow2 = sheet.getRow(3);
            short lastCellNum = minitorPointRow.getLastCellNum();
            int cellNum = 5;
            HashMap<String, Integer> newFieldConfig = new HashMap<>(SHEET_FIELD_CONFIG);
            for (Map<String, Object> monitorPoint : monitorPointResult) {
                String id = StrUtil.toString(monitorPoint.get("id"));
                String name = StrUtil.toString(monitorPoint.get("name"));
                newFieldConfig.put(id + "Price", cellNum++);

                short curCellNum = lastCellNum++;
                XSSFCell cell1 = minitorPointRow.createCell(curCellNum);
                cell1.setCellStyle(minitorPointRow.getCell(3).getCellStyle());
                cell1.setCellValue(name);

                XSSFCell cell2 = minitorPointRow2.createCell(curCellNum);
                cell2.setCellStyle(minitorPointRow2.getCell(3).getCellStyle());
                cell2.setCellValue("零售价");
            }

            //合并单元格
            sheet.removeMergedRegion(0);
            sheet.removeMergedRegion(0);
            sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, minitorPointRow.getLastCellNum() - 1));
            sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, minitorPointRow.getLastCellNum() - 1));

            //遍历列表给excel赋值
            for (int i = 0; i < priceResult.size(); i++) {
                setRowFromEntityObj(priceResult.get(i), sheet, newFieldConfig);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        String fileName = getReportTitle(priceSearchVo);
        exportFileInfo.put("excel_file_name", fileName + ".xlsx");
        exportFileInfo.put("excel_file_content", workbook);
        return exportFileInfo;
    }

    @Override
    public Map<String, Object> exportExcelV3(PriceSearchVo priceSearchVo, PriceTask priceTask) {
        //方法返回excel文件信息
        Map<String, Object> exportFileInfo = new HashMap<>(4);
        Map<String, Object> reportExcelConfig = PriceReportConstants.getConfigByPriceTask(priceTask);
        String sheetName = reportExcelConfig.get("sheet").toString();
        int startRow = (Integer)reportExcelConfig.get("startRow");
        Map<String, Integer> fixedFieldConfig = (Map<String, Integer>) reportExcelConfig.get("fields");

        //加载模板文件
        InputStream stream = FileUtil.getInputStream(templateFilePath + reportExcelConfig.get("file"));
        XSSFWorkbook workbook;
        try {
            workbook = new XSSFWorkbook(stream);

            //默认显示当前sheet
            int sheetIndex = workbook.getSheetIndex(sheetName);
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                if (i == sheetIndex) {
                    workbook.setActiveSheet(sheetIndex);
                } else {
                    workbook.setSheetHidden(i, true);
                }
            }

            Map<String, List<Map<String, Object>>> queryData = selectPageV3(priceSearchVo, priceTask);
            List<Map<String, Object>> priceResult = queryData.get("priceResult");
            List<Map<String, Object>> monitorPointResult = queryData.get("monitorPointResult");
            if(CollUtil.isEmpty(priceResult)){
                exportFileInfo.put("excel_file_name", sheetName + ".xlsx");
                exportFileInfo.put("excel_file_content", workbook);
                return exportFileInfo;
            }

            //设置表头标题
            XSSFSheet sheet = workbook.getSheet(sheetName);
            XSSFRow titleRow = sheet.getRow(0);
            XSSFCell titleCell = titleRow.getCell(0);
            String newTitle = sheetName.replaceAll("\\d{1,2}、", "");
            titleCell.setCellValue(newTitle);

            //设置表头监测点名称
            HashMap<String, Integer> newFieldConfig = fillSheetTableHeaderTitle(sheet, startRow, fixedFieldConfig, monitorPointResult, priceTask);

            //合并标题
            List<String> noneMergeReportType = Arrays.asList("T007", "T009", "T014");
            if (!noneMergeReportType.contains(priceTask.getDkTemplateTypesCode())) {
                XSSFRow minitorPointRow = sheet.getRow(startRow - 1);
                sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, minitorPointRow.getLastCellNum() - 1));
            }

            //遍历列表给excel赋值
            for (int i = 0; i < priceResult.size(); i++) {
                setRowFromEntityObjV3(priceResult.get(i), sheet, newFieldConfig, startRow);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        exportFileInfo.put("excel_file_name", sheetName.replaceAll("\\d{1,2}、", "") + ".xlsx");
        exportFileInfo.put("excel_file_content", workbook);
        return exportFileInfo;
    }

    /**
     * 填充动态表头标题
     *
     * @param sheet
     * @param startRow
     * @param fixedFieldConfig
     * @param monitorPointResult
     * @param priceTask
     * @return
     */
    @NotNull
    private static HashMap<String, Integer> fillSheetTableHeaderTitle(XSSFSheet sheet, int startRow, Map<String, Integer> fixedFieldConfig, List<Map<String, Object>> monitorPointResult, PriceTask priceTask) {
        HashMap<String, Integer> newFieldConfig = new HashMap<>(fixedFieldConfig);

        XSSFRow minitorPointRow = sheet.getRow(startRow - 2);
        XSSFRow minitorPointRow2 = sheet.getRow(startRow - 1);
        int fixedCellNum = minitorPointRow.getLastCellNum();
        int startCell = minitorPointRow.getLastCellNum();

        List<String> noneMergerCell = Arrays.asList("T002", "T003", "T004", "T005", "T006");
        List<String> needMergerThreeCell = Arrays.asList("T008", "T010", "T011", "T012", "T013");

        for (Map<String, Object> monitorPoint : monitorPointResult) {
            String id = StrUtil.toString(monitorPoint.get("id"));
            String name = StrUtil.toString(monitorPoint.get("name"));
            int curCellNum = startCell++;

            if ("T001".equals(priceTask.getDkTemplateTypesCode())) {
                XSSFCell cell1 = minitorPointRow.createCell(curCellNum);
                XSSFCell cell12 = minitorPointRow.createCell(curCellNum + 1);
                cell1.setCellStyle(minitorPointRow.getCell(4).getCellStyle());
                cell12.setCellStyle(minitorPointRow.getCell(4).getCellStyle());
                cell1.setCellValue(name);
                sheet.addMergedRegion(new CellRangeAddress(startRow - 2, startRow - 2, curCellNum, curCellNum + 1));

                XSSFCell cell3 = minitorPointRow2.createCell(curCellNum);
                cell3.setCellStyle(minitorPointRow.getCell(4).getCellStyle());
                cell3.setCellValue("农贸市场零售价");
                newFieldConfig.put(id + "MarketPrice", curCellNum);

                XSSFCell cell4 = minitorPointRow2.createCell(curCellNum + 1);
                cell4.setCellStyle(minitorPointRow.getCell(4).getCellStyle());
                cell4.setCellValue("超市零售价");
                newFieldConfig.put(id + "SuperPrice", curCellNum + 1);

                //一次创建两列 所有再+1
                startCell++;
            }

            if (noneMergerCell.contains(priceTask.getDkTemplateTypesCode())) {
                XSSFCell cell1 = minitorPointRow2.createCell(curCellNum);
                cell1.setCellStyle(minitorPointRow2.getCell(4).getCellStyle());
                cell1.setCellValue(name);
                newFieldConfig.put(id + "MarketPrice", curCellNum);
            }

            if (needMergerThreeCell.contains(priceTask.getDkTemplateTypesCode())) {
                XSSFCell cell1 = minitorPointRow.createCell(curCellNum);
                XSSFCell cell12 = minitorPointRow.createCell(curCellNum + 1);
                XSSFCell cell13 = minitorPointRow.createCell(curCellNum + 2);
                cell1.setCellStyle(minitorPointRow.getCell(3).getCellStyle());
                cell12.setCellStyle(minitorPointRow.getCell(3).getCellStyle());
                cell13.setCellStyle(minitorPointRow.getCell(3).getCellStyle());
                cell1.setCellValue(name);
                sheet.addMergedRegion(new CellRangeAddress(startRow - 2, startRow - 2, curCellNum, curCellNum + 2));

                XSSFCell cell21 = minitorPointRow2.createCell(curCellNum);
                cell21.setCellStyle(minitorPointRow.getCell(3).getCellStyle());
                cell21.setCellValue(minitorPointRow2.getCell(fixedCellNum-5).getStringCellValue());
                newFieldConfig.put(id + "MarketPrice", curCellNum);

                XSSFCell cell22 = minitorPointRow2.createCell(curCellNum + 1);
                cell22.setCellStyle(minitorPointRow.getCell(3).getCellStyle());
                cell22.setCellValue(minitorPointRow2.getCell(fixedCellNum-4).getStringCellValue());
                newFieldConfig.put(id + "Stock", curCellNum + 1);

                XSSFCell cell23 = minitorPointRow2.createCell(curCellNum + 2);
                cell23.setCellStyle(minitorPointRow.getCell(3).getCellStyle());
                cell23.setCellValue(minitorPointRow2.getCell(fixedCellNum-3).getStringCellValue());
                newFieldConfig.put(id + "Sale", curCellNum + 2);

                //一次创建3列 所有再+2
                startCell++;
                startCell++;
            }
        }
        return newFieldConfig;
    }

    private String getReportTitle(PriceSearchVo priceSearchVo) {
        if (StrUtil.equals("单次", priceSearchVo.getDatePicker())) {
            priceSearchVo.setPriceType("报");
        }
        return "居民生活消费（食）品零售价格监测priceType表(九农贸) (date)".replace("priceType", priceSearchVo.getPriceType())
                .replace("date", priceSearchVo.getDatePicker());
    }

    @Override
    public Result getDateList(PriceSearchVo priceSearchVo) {
        Result result = new Result();

        //查询对应报表类型任务id集合
        List<PriceTask> priceTasks = priceTaskMapper.selectList(Wrappers.<PriceTask>lambdaQuery()
                .eq(PriceTask::getScheduleType, StrUtil.isEmpty(priceSearchVo.getPriceType()) ? "-1" : priceSearchVo.getPriceType()));
        List<Integer> priceTaskIds = priceTasks.stream().map(PriceTask::getId).collect(Collectors.toList());

        if (CollUtil.isEmpty(priceTaskIds)) {
            priceTaskIds = Collections.singletonList(-1);
        }

        //根据上一步结果查询对应报表类型的时间集合
        List<TaskProcessRelation> taskProcessRelations = taskProcessRelationMapper.selectList(Wrappers.<TaskProcessRelation>lambdaQuery()
                .in(TaskProcessRelation::getTaskId, priceTaskIds));
        List<String> dateList = taskProcessRelations.stream()
                .map(TaskProcessRelation::getStartTime)
                .distinct()
                .sorted()
                .collect(Collectors.toList());

        result.addData("dateList", dateList);
        return result;
    }

    @Override
    public Result getDateListV3(PriceSearchVo priceSearchVo) {
        Result result = new Result();
        //根据上一步结果查询对应报表类型的时间集合
        List<TaskProcessRelation> taskProcessRelations = taskProcessRelationMapper.selectList(Wrappers.<TaskProcessRelation>lambdaQuery()
                .in(TaskProcessRelation::getTaskId, StrUtil.isEmpty(priceSearchVo.getTaskId()) ? "-1" : priceSearchVo.getTaskId()));
        List<String> dateList = taskProcessRelations.stream()
                .map(TaskProcessRelation::getStartTime)
                .distinct()
                .sorted()
                .collect(Collectors.toList());

        result.addData("dateList", dateList);
        return result;
    }

    @Override
    public Result getTaskList(PriceSearchVo priceSearchVo) {
        Result result = new Result();

        //根据报价日期查询taskId集合
        List<TaskProcessRelation> taskProcessRelations = taskProcessRelationMapper.selectList(Wrappers.<TaskProcessRelation>lambdaQuery()
                .eq(TaskProcessRelation::getStartTime, StrUtil.isEmpty(priceSearchVo.getDatePicker()) ? "-1" : priceSearchVo.getDatePicker()));
        List<Integer> taskIds = taskProcessRelations.stream().map(TaskProcessRelation::getTaskId).distinct().collect(Collectors.toList());
        if (CollUtil.isEmpty(taskIds)) {
            taskIds = Collections.singletonList(-1);
        }

        //查询任务信息
        List<PriceTask> priceTasks = priceTaskMapper.selectList(Wrappers.<PriceTask>lambdaQuery()
                .in(PriceTask::getId, taskIds)
                .eq(PriceTask::getScheduleType, priceSearchVo.getPriceType()));
        List<Map<String, Object>> taskList = new ArrayList<>();
        for (PriceTask priceTask : priceTasks) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", priceTask.getId());
            map.put("name", priceTask.getTaskName());
            taskList.add(map);
        }

        result.addData("taskList", taskList);

        return result;
    }

    @Override
    public Result getProductTypes() {
        Result result = new Result();
        List<ProductInfo> productInfos = productInfoMapper.selectList(Wrappers.<ProductInfo>lambdaQuery()
                .isNull(ProductInfo::getParentId));

        List<String> productTypes = productInfos.stream()
                .map(ProductInfo::getName)
                .sorted(Comparator.reverseOrder())
                .collect(Collectors.toList());
        result.addData("productTypes", productTypes);

        return result;
    }

    @Override
    public List<Map<String, String>> selectMonitorPoints(String type, String district) {
        return Collections.emptyList();
    }

    /**
     * 表格Row赋值
     *
     * @param recordBean
     * @param sheet
     * @param newFieldConfig
     */
    private void setRowFromEntityObj(Object recordBean,
                                     XSSFSheet sheet, HashMap<String, Integer> newFieldConfig) {
        XSSFRow row = PoiHelper.getNextXssfRow(sheet, 4);

        //字段对应关系（此处导出当审核菜单时所有字段的值都要导出）
        for (Map.Entry<String, Integer> fieldEntry : newFieldConfig.entrySet()) {
            String fieldName = fieldEntry.getKey();

            int columnNumber = fieldEntry.getValue();
            XSSFCell cell = row.getCell(columnNumber);
            if (Objects.isNull(cell)) {
                XSSFCell baseCell = row.getCell(3);
                cell = row.createCell(columnNumber);
                cell.setCellStyle(baseCell.getCellStyle());
            }

            Object value = BeanUtil.getFieldValue(recordBean, fieldName);

            if (value != null) {
                PoiHelper.setValueToCellV2(cell, value);
            }
        }
    }

    /**
     * 表格Row赋值
     *
     * @param recordBean
     * @param sheet
     * @param newFieldConfig
     */
    private void setRowFromEntityObjV3(Object recordBean,
                                     XSSFSheet sheet, HashMap<String, Integer> newFieldConfig, int startRow) {
        XSSFRow row = PoiHelper.getNextXssfRow(sheet, startRow);

        //字段对应关系（此处导出当审核菜单时所有字段的值都要导出）
        for (Map.Entry<String, Integer> fieldEntry : newFieldConfig.entrySet()) {
            String fieldName = fieldEntry.getKey();

            int columnNumber = fieldEntry.getValue();
            XSSFCell cell = row.getCell(columnNumber);
            if (Objects.isNull(cell)) {
                XSSFCell baseCell = row.getCell(3);
                cell = row.createCell(columnNumber);
                cell.setCellStyle(baseCell.getCellStyle());
            }

            Object value = BeanUtil.getFieldValue(recordBean, fieldName);

            if (value != null) {
                PoiHelper.setValueToCellV2(cell, value);
            }
        }
    }

    /**
     * 根据各区县各商品价格信息生成所需报表信息
     *
     * @param basePriceData
     * @return
     */
    private List<Map<String, Object>> generateReportData(List<Map<String, Object>> basePriceData) {
        ArrayList<Map<String, Object>> priceResult = new ArrayList<>();

        //当前数据包含的监测点列表
        List<String> monitorPointList = basePriceData.stream()
                .map(d -> StrUtil.toString(d.get("monitorPoint")))
                .distinct()
                .collect(Collectors.toList());

        //按 商品类别-商品名称-规格-计量单位 抽取包含的商品信息
        List<String> productList = basePriceData.stream()
                .map(p -> joinStr(StrPool.AT, p.get("type"), p.get("name"), p.get("kind"), p.get("unit")))
                .distinct()
                .sorted()
                .collect(Collectors.toList());

        Map<String, List<Map<String, Object>>> productPriceDataMapping = basePriceData.stream().collect(Collectors.groupingBy(
                p -> joinStr(StrPool.AT, p.get("type"), p.get("name"), p.get("kind"), p.get("unit"))
        ));

        //按商品类别-商品名称-规格-计量单位对数据进行分组
        String type = " ";
        int number = 0;
        //按商品列表形式拼接各区县采价点的价格信息
        for (String product : productList) {
            HashMap<String, Object> record = new HashMap<>();
            List<String> productInfo = StrUtil.split(product, StrPool.AT);

            //商品类别
            if (!StrUtil.equals(type, productInfo.get(0))) {
                HashMap<String, Object> typeRecord = new HashMap<>();
                typeRecord.put("name", NUMBER_STR.get(number) + productInfo.get(0));
                priceResult.add(typeRecord);
                type = productInfo.get(0);
            }

            //序号
            record.put("no", ++number);
            //名称
            record.put("name", productInfo.get(1));
            //规格
            record.put("kind", productInfo.get(2));
            //计量单位
            record.put("unit", productInfo.get(3));

            List<Map<String, Object>> priceData = productPriceDataMapping.get(product);
            Map<String, List<Map<String, Object>>> monitorPointPriceDataMapping = priceData.stream().collect(Collectors.groupingBy(
                    p -> StrUtil.toString(p.get("monitorPoint"))
            ));

            ArrayList<Double> prices = new ArrayList<>();
            for (String monitorPoint : monitorPointList) {
                List<Map<String, Object>> priceList = monitorPointPriceDataMapping.get(monitorPoint);
                if (CollUtil.isNotEmpty(priceList)) {
                    Object priceObj = priceList.get(0).get("price");
                    if (NumberUtil.isNumber(StrUtil.toStringOrNull(priceObj))) {
                        double price = Double.parseDouble(StrUtil.toString(priceObj));
                        record.put(monitorPoint + "Price", price);
                        prices.add(price);
                    }
                }
            }
            //平均价格
            double avgPrice = prices.stream().mapToDouble(Double::doubleValue).average().orElse(0d);
            record.put("avgPrice", String.format("%.2f", avgPrice));

            priceResult.add(record);
        }

        return priceResult;
    }

    /**
     * 根据各区县各商品价格信息生成所需报表信息
     *
     * @param basePriceData
     * @param allMonitorPoints
     * @param productPriceAlarmMapping
     * @param priceTask
     * @return
     */
    private List<Map<String, Object>> generateReportDataV3(List<Map<String, Object>> basePriceData, ArrayList<Map<String, Object>> allMonitorPoints, Map<String, String> productPriceAlarmMapping, PriceTask priceTask) {
        ArrayList<Map<String, Object>> priceResult = new ArrayList<>();
        Map<String, String> monitorMapping = allMonitorPoints.stream().collect(Collectors.toMap(m -> m.get("id").toString(), m -> m.get("name").toString()));
        //当前数据包含的监测点列表
        List<String> monitorPointList = basePriceData.stream()
                .map(d -> StrUtil.toString(d.get("monitorPoint")))
                .distinct()
                .collect(Collectors.toList());

        //按 商品类别-商品名称-规格-计量单位 抽取包含的商品信息
        List<String> productList = basePriceData.stream()
                .map(p -> StrUtil.toString(p.get("product")))
                .distinct()
                .sorted()
                .collect(Collectors.toList());

        //按商品对数据进行分组
        Map<String, List<Map<String, Object>>> productPriceDataMapping = basePriceData.stream().collect(Collectors.groupingBy(
                p -> StrUtil.toString(p.get("productId"))
        ));
        LinkedHashMap<String, List<Map<String, Object>>> new_productPriceDataMapping = new LinkedHashMap<>();
        JSONArray jsonArray = JSONUtil.parseArray(priceTask.getProductMonitorRelations());
//        Map<String, List<Map<String, Object>>> finalProductPriceDataMapping = productPriceDataMapping;
//        jsonArray.forEach(obj -> {
//            JSONObject one = (JSONObject) obj;
//            String productId = one.getStr("productId");
//            new_productPriceDataMapping.putLast(productId, finalProductPriceDataMapping.get(productId));
//        });
//        log.info("new_productPriceDataMapping={}", JSONUtil.toJsonStr(new_productPriceDataMapping));
//        productPriceDataMapping = new_productPriceDataMapping;
//        log.info("productPriceDataMapping={}", JSONUtil.toJsonStr(productPriceDataMapping));
        //按商品类别-商品名称-规格-计量单位对数据进行分组
        String type = " ";
        int number = 0;
        //按商品列表形式拼接各区县采价点的价格信息
//        if (CollectionUtil.isNotEmpty(productList)) {
//            HashMap<String, Object> type_record = new HashMap<>();
//            type_record.put("no", ++number);
//            type_record.put("name", StrUtil.split(productList.get(0), "#@#").get(0));
//            type_record.put("pType", StrUtil.split(productList.get(0), "#@#").get(0));
//            priceResult.add(type_record);
//        }

        for (String product : productList) {
            HashMap<String, Object> record = new HashMap<>();
            List<String> productInfo = StrUtil.split(product, "#@#");
            String productId = productInfo.get(4);


            //商品类别
            if (needProductType(priceTask.getDkTemplateTypesCode())) {
                if (!StrUtil.equals(type, productInfo.get(0))) {
//                    HashMap<String, Object> typeRecord = new HashMap<>();
//                    typeRecord.put("name", NUMBER_STR.get(number) + productInfo.get(0));
//                    priceResult.add(typeRecord);
//                    type = productInfo.get(0);
                }
            }

            //序号
            record.put("no", ++number);


            record.put("productId", productId);
            record.put("name", productInfo.get(1));
            record.put("pType", productInfo.get(0));
            //规格
            record.put("kind", productInfo.get(2));
            //计量单位
            record.put("unit", productInfo.get(3));
            //上报频次
            record.put("scheduleType", priceTask.getScheduleType());
            //价格预警幅度
            record.put("priceAlarmPercent", productPriceAlarmMapping.get(productId));

            List<Map<String, Object>> priceData = productPriceDataMapping.get(productId);
            switch (priceTask.getDkTemplateTypesCode()) {
                case "T001":
                    addData2ListByPriceTask4Type1(priceData, allMonitorPoints, priceResult, record);
                    break;
                case "T002":
                case "T003":
                case "T004":
                case "T005":
                case "T006":
                    addData2ListByPriceTask4Type2(priceData, allMonitorPoints, priceResult, record);
                    break;
                case "T007":
                    addData2ListByPriceTask4Type3(priceData, allMonitorPoints, priceResult, record);
                    break;
                case "T008":
                case "T010":
                case "T011":
                case "T012":
                case "T013":
                    addData2ListByPriceTask4Type4(priceData, allMonitorPoints, priceResult, record);
                    break;
                case "T009":
                case "T014":
                    addData2ListByPriceTask4Type5(priceData, monitorMapping, priceResult, record);
                    break;
                default:
            }

        }

        return priceResult;
    }

    private void addData2ListByPriceTask4Type1(List<Map<String, Object>> priceData, ArrayList<Map<String, Object>> allMonitorPoints, ArrayList<Map<String, Object>> priceResult, HashMap<String, Object> record) {
        //数据按监测点分组
        Map<String, List<Map<String, Object>>> monitorPointPriceDataMapping = priceData.stream().collect(Collectors.groupingBy(
                p -> StrUtil.toString(p.get("monitorPoint"))
        ));

        ArrayList<Double> marketPrices = new ArrayList<>();
        ArrayList<Double> superPrices = new ArrayList<>();
        //按监测点遍历
        for (Map<String, Object> monitorPoint : allMonitorPoints) {
            String monitorId = monitorPoint.get("id").toString();
            List<Map<String, Object>> priceList = monitorPointPriceDataMapping.get(monitorId);
            if (CollUtil.isNotEmpty(priceList)) {
                for (Map<String, Object> info : priceList) {
                    Object priceObj = info.get("indexValue");
                    Double price = null;
                    if (NumberUtil.isNumber(StrUtil.toStringOrNull(priceObj))) {
                        price = (double) priceObj;
                    }
                    if ("农贸市场零售价".equals(info.get("indexType").toString())) {
                        record.put(monitorId + "MarketPrice", price);
                        if (price != null) {
                            marketPrices.add(price);
                        }
                    }
                    if ("超市零售价".equals(info.get("indexType").toString())) {
                        record.put(monitorId + "SuperPrice", price);
                        if (price != null) {
                            superPrices.add(price);
                        }
                    }
                }
            }
        }

        //平均价格
        double avgMarketPrice = marketPrices.stream().mapToDouble(Double::doubleValue).average().orElse(0d);
        double avgSuperPrice = superPrices.stream().mapToDouble(Double::doubleValue).average().orElse(0d);
        record.put("avgMarketPrice", String.format("%.2f", avgMarketPrice));
        record.put("avgSuperPrice", String.format("%.2f", avgSuperPrice));

        priceResult.add(record);
    }

    private void addData2ListByPriceTask4Type2(List<Map<String, Object>> priceData, ArrayList<Map<String, Object>> allMonitorPoints, ArrayList<Map<String, Object>> priceResult, HashMap<String, Object> record) {
        //数据按监测点分组
        Map<String, List<Map<String, Object>>> indexTypePriceDataMapping = priceData.stream().collect(Collectors.groupingBy(
                p -> StrUtil.toString(p.get("indexType"))
        ));

        //按监测点遍历
        if (CollUtil.isNotEmpty(indexTypePriceDataMapping)) {
            indexTypePriceDataMapping.forEach((indexType, priceList) -> {
                record.put("indexType", indexType);

                ArrayList<Double> prices = new ArrayList<>();
                for (Map<String, Object> monitorData : priceList) {
                    Object priceObj = monitorData.get("indexValue");
                    Double price = null;
                    if (NumberUtil.isNumber(StrUtil.toStringOrNull(priceObj))) {
                        price = (double) priceObj;
                        prices.add(price);
                        record.put(monitorData.get("monitorPoint") + "MarketPrice", String.format("%.2f", price));
                    }

                }
                //平均价格
                double avgMarketPrice = prices.stream().mapToDouble(Double::doubleValue).average().orElse(0d);
                record.put("avgMarketPrice", String.format("%.2f", avgMarketPrice));

                priceResult.add(new HashMap<>(record));
            });
        }
    }

    private void addData2ListByPriceTask4Type3(List<Map<String, Object>> priceData, ArrayList<Map<String, Object>> allMonitorPoints, ArrayList<Map<String, Object>> priceResult, HashMap<String, Object> record) {
        //数据按监测点分组
        Map<String, List<Map<String, Object>>> monitorPointPriceDataMapping = priceData.stream().collect(Collectors.groupingBy(
                p -> StrUtil.toString(p.get("monitorPoint"))
        ));

        //按监测点遍历
        for (Map<String, Object> monitorPoint : allMonitorPoints) {
            String monitorId = monitorPoint.get("id").toString();
            String monitorName = monitorPoint.get("name").toString();
            List<Map<String, Object>> priceList = monitorPointPriceDataMapping.get(monitorId);
            record.put("monitorName", monitorName);
            if (CollUtil.isNotEmpty(priceList)) {
                for (Map<String, Object> info : priceList) {
                    if ("收购价格".equals(info.get("indexType").toString())) {
                        Object priceObj = priceList.get(0).get("price");
                        if (NumberUtil.isNumber(StrUtil.toStringOrNull(priceObj))) {
                            double price = Double.parseDouble(StrUtil.toString(priceObj));
                            record.put("purchasePrice", price);
                        }
                    }
                    if ("出厂价格".equals(info.get("indexType").toString())) {
                        Object priceObj = priceList.get(0).get("price");
                        if (NumberUtil.isNumber(StrUtil.toStringOrNull(priceObj))) {
                            double price = Double.parseDouble(StrUtil.toString(priceObj));
                            record.put("factoryPrice", price);
                        }
                    }
                }
            }
            priceResult.add(new HashMap<>(record));
        }
    }

    private void addData2ListByPriceTask4Type4(List<Map<String, Object>> priceData, ArrayList<Map<String, Object>> allMonitorPoints, ArrayList<Map<String, Object>> priceResult, HashMap<String, Object> record) {
        //数据按指标类型分组
        Map<String, List<Map<String, Object>>> indexTypePriceDataMapping = priceData.stream().collect(Collectors.groupingBy(
                p -> StrUtil.toString(p.get("indexType"))
        ));

        HashMap<String, Object> monitorStockMapping = new HashMap<>();
        List<Map<String, Object>> stockData = indexTypePriceDataMapping.get("库存量");
        if(CollUtil.isEmpty(stockData)){
            stockData = indexTypePriceDataMapping.get("存栏量");
        }
        if (CollUtil.isNotEmpty(stockData)) {
            for (Map<String, Object> stockDatum : stockData) {
                String monitorPoint = stockDatum.get("monitorPoint").toString();
                Object indexValue = stockDatum.get("indexValue");
                monitorStockMapping.put(monitorPoint, indexValue);
            }
        }
        indexTypePriceDataMapping.remove("库存量");
        indexTypePriceDataMapping.remove("存栏量");


        HashMap<String, Object> monitorSaleMapping = new HashMap<>();
        List<Map<String, Object>> saleData = indexTypePriceDataMapping.get("销售量");
        if(CollUtil.isEmpty(saleData)){
            saleData = indexTypePriceDataMapping.get("出栏量");
        }
        if (CollUtil.isNotEmpty(saleData)) {
            for (Map<String, Object> saleDatum : saleData) {
                String monitorPoint = saleDatum.get("monitorPoint").toString();
                Object indexValue = saleDatum.get("indexValue");
                monitorSaleMapping.put(monitorPoint, indexValue);
            }
        }

        indexTypePriceDataMapping.remove("销售量");
        indexTypePriceDataMapping.remove("出栏量");

        //按监测点遍历
        if (CollUtil.isNotEmpty(indexTypePriceDataMapping)) {
            indexTypePriceDataMapping.forEach((indexType, priceList) -> {
                record.put("indexType", indexType);

                ArrayList<Double> prices = new ArrayList<>();
                ArrayList<Double> stocks = new ArrayList<>();
                ArrayList<Double> sales = new ArrayList<>();
                for (Map<String, Object> monitorData : priceList) {
                    String monitorId = monitorData.get("monitorPoint").toString();
                    Object priceObj = monitorData.get("indexValue");
                    Double price = null;
                    if (NumberUtil.isNumber(StrUtil.toStringOrNull(priceObj))) {
                        price = (double) priceObj;
                        prices.add(price);
                        record.put(monitorId + "MarketPrice", String.format("%.2f", price));
                    }

                    Double stock = null;
                    Object stockObj = monitorStockMapping.get(monitorId);
                    if (NumberUtil.isNumber(StrUtil.toStringOrNull(stockObj))) {
                        stock = (double) stockObj;
                        stocks.add(stock);
                        record.put(monitorId + "Stock", String.format("%.2f", stock));
                    }

                    Double sale = null;
                    Object saleObj = monitorSaleMapping.get(monitorId);
                    if (NumberUtil.isNumber(StrUtil.toStringOrNull(saleObj))) {
                        sale = (double) saleObj;
                        sales.add(sale);
                        record.put(monitorId + "Sale", String.format("%.2f", sale));
                    }
                }
                //平均价格
                double avgMarketPrice = prices.stream().mapToDouble(Double::doubleValue).average().orElse(0d);
                record.put("avgMarketPrice", String.format("%.2f", avgMarketPrice));
                if(CollUtil.isNotEmpty(monitorStockMapping)){
                    double avgStock = stocks.stream().mapToDouble(Double::doubleValue).average().orElse(0d);
                    record.put("avgStock", String.format("%.2f", avgStock));
                }
                if(CollUtil.isNotEmpty(monitorSaleMapping)){
                    double avgSale = sales.stream().mapToDouble(Double::doubleValue).average().orElse(0d);
                    record.put("avgSale", String.format("%.2f", avgSale));
                }

                priceResult.add(new HashMap<>(record));
            });
        }
    }

    private void addData2ListByPriceTask4Type5(List<Map<String, Object>> priceData, Map<String, String> monitorPoints, ArrayList<Map<String, Object>> priceResult, HashMap<String, Object> record) {
        //数据按指标类型分组
        Map<String, List<Map<String, Object>>> indexTypePriceDataMapping = priceData.stream().collect(Collectors.groupingBy(
                p -> StrUtil.toString(p.get("indexType"))
        ));

        HashMap<String, Object> monitorStockMapping = new HashMap<>();
        List<Map<String, Object>> stockData = indexTypePriceDataMapping.get("库存量");
        if(CollUtil.isNotEmpty(stockData)){
            for (Map<String, Object> stockDatum : stockData) {
                String monitorPoint = stockDatum.get("monitorPoint").toString();
                Object indexValue = stockDatum.get("indexValue");
                monitorStockMapping.put(monitorPoint, indexValue);
            }
        }
        indexTypePriceDataMapping.remove("库存量");


        HashMap<String, Object> monitorSaleMapping = new HashMap<>();
        List<Map<String, Object>> saleData = indexTypePriceDataMapping.get("销售量");
        if(CollUtil.isNotEmpty(saleData)){
            for (Map<String, Object> saleDatum : saleData) {
                String monitorPoint = saleDatum.get("monitorPoint").toString();
                Object indexValue = saleDatum.get("indexValue");
                monitorSaleMapping.put(monitorPoint, indexValue);
            }
        }
        indexTypePriceDataMapping.remove("销售量");


        //按监测点遍历
        if (CollUtil.isNotEmpty(indexTypePriceDataMapping)) {
            indexTypePriceDataMapping.forEach((indexType, priceList) -> {
                record.put("indexType", indexType);
                for (Map<String, Object> monitorData : priceList) {
                    String monitorId = monitorData.get("monitorPoint").toString();
                    record.put("monitorName", monitorPoints.get(monitorId));
                    Object priceObj = monitorData.get("indexValue");
                    Double price = null;
                    if (NumberUtil.isNumber(StrUtil.toStringOrNull(priceObj))) {
                        price = (double) priceObj;
                        record.put("avgMarketPrice", String.format("%.2f", price));
                    }

                    Double stock = null;
                    Object stockObj = monitorStockMapping.get(monitorId);
                    if (NumberUtil.isNumber(StrUtil.toStringOrNull(stockObj))) {
                        stock = (double) stockObj;
                        record.put("avgStock", String.format("%.2f", stock));
                    }

                    Double sale = null;
                    Object saleObj = monitorSaleMapping.get(monitorId);
                    if (NumberUtil.isNumber(StrUtil.toStringOrNull(saleObj))) {
                        sale = (double) saleObj;
                        record.put("avgSale", String.format("%.2f", sale));
                    }
                    priceResult.add(new HashMap<>(record));
                }
            });
        }
    }

    /**
     * 返回结果中是否包含商品类别
     * @param dkTemplateTypesCode
     * @return
     */
    private boolean needProductType(String dkTemplateTypesCode) {
        return StrUtil.equals(dkTemplateTypesCode, "T001")
                || StrUtil.equals(dkTemplateTypesCode, "T002")
                || StrUtil.equals(dkTemplateTypesCode, "T003")
                || StrUtil.equals(dkTemplateTypesCode, "T005")
                || StrUtil.equals(dkTemplateTypesCode, "T006");
    }

    private String joinStr(String conjunction, Object... objects) {
        if (ArrayUtil.isEmpty(objects)) {
            return "";
        }
        return Arrays.stream(objects)
                .map(o -> o == null ? "" : o.toString())
                .collect(Collectors.joining(conjunction));
    }
}
